{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "什么是PyTorch？\n",
    "================\n",
    "\n",
    "PyTorch是一个基于Python的科学计算包，它主要有两个用途：\n",
    "\n",
    "-  类似Numpy但是能利用GPU加速\n",
    "-  一个非常灵活和快速的用于深度学习的研究平台\n",
    "\n",
    "入门\n",
    "---------------\n",
    "\n",
    "Tensor\n",
    "^^^^^^^\n",
    "\n",
    "Tensor类似与NumPy的ndarray，但是可以用GPU加速。\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造一个5x3的矩阵，未初始化：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-8.9602e+25,  4.5560e-41,  1.2859e-37],\n",
      "        [ 0.0000e+00,  0.0000e+00,  0.0000e+00],\n",
      "        [ 0.0000e+00,  0.0000e+00,  0.0000e+00],\n",
      "        [ 0.0000e+00,  0.0000e+00,  0.0000e+00],\n",
      "        [ 6.8322e-07,  2.1027e+20, -6.3528e-11]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.empty(5, 3)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造一个随机初始化的矩阵：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[0.7708, 0.9620, 0.0062],\n",
      "        [0.6762, 0.8512, 0.3808],\n",
      "        [0.1306, 0.0090, 0.2810],\n",
      "        [0.4013, 0.2433, 0.8295],\n",
      "        [0.4082, 0.4299, 0.7848]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.rand(5, 3)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造一个用零初始化的矩阵，它的类型(dtype)是long：\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.zeros(5, 3, dtype=torch.long)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用Python的数组来构造Tensor：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([5.5000, 3.0000])\n"
     ]
    }
   ],
   "source": [
    "x = torch.tensor([5.5, 3])\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从已有的tensor信息(size和dtype)来构造tensor。我们也可以用不同的dtype来构造。\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1., 1., 1.],\n",
      "        [1., 1., 1.],\n",
      "        [1., 1., 1.],\n",
      "        [1., 1., 1.],\n",
      "        [1., 1., 1.]], dtype=torch.float64)\n",
      "tensor([[-1.4145,  2.3707, -1.2691],\n",
      "        [-0.5762,  0.3905, -0.7635],\n",
      "        [-0.3051,  0.2491, -0.7909],\n",
      "        [-0.6256, -1.6052,  1.2538],\n",
      "        [ 1.0184,  0.4827,  1.4783]])\n"
     ]
    }
   ],
   "source": [
    "x = x.new_ones(5, 3, dtype=torch.double)      # new_* methods take in sizes\n",
    "print(x)\n",
    "\n",
    "x = torch.randn_like(x, dtype=torch.float)    # override dtype!\n",
    "print(x)                                      # result has the same size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "查看它的size\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([5, 3])\n"
     ]
    }
   ],
   "source": [
    "print(x.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\"><h4>注意</h4><p>``torch.Size``其实是一个tuple，因此它支持所有的tuple操作</p></div>\n",
    "\n",
    "Operation\n",
    "^^^^^^^^^^\n",
    "同一个operation可能有多种语法。下面是第一种使用加法的语法：\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.9843,  2.5384, -0.9066],\n",
      "        [-0.2077,  0.9302, -0.7118],\n",
      "        [ 0.0234,  1.1288, -0.7171],\n",
      "        [-0.0322, -0.9226,  2.1789],\n",
      "        [ 1.4417,  0.5709,  2.4731]])\n"
     ]
    }
   ],
   "source": [
    "y = torch.rand(5, 3)\n",
    "print(x + y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用加法的第二种语法：\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.9843,  2.5384, -0.9066],\n",
      "        [-0.2077,  0.9302, -0.7118],\n",
      "        [ 0.0234,  1.1288, -0.7171],\n",
      "        [-0.0322, -0.9226,  2.1789],\n",
      "        [ 1.4417,  0.5709,  2.4731]])\n"
     ]
    }
   ],
   "source": [
    "print(torch.add(x, y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给加法提供返回值(而不是生成一个新的返回值)：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.9843,  2.5384, -0.9066],\n",
      "        [-0.2077,  0.9302, -0.7118],\n",
      "        [ 0.0234,  1.1288, -0.7171],\n",
      "        [-0.0322, -0.9226,  2.1789],\n",
      "        [ 1.4417,  0.5709,  2.4731]])\n"
     ]
    }
   ],
   "source": [
    "result = torch.empty(5, 3)\n",
    "torch.add(x, y, out=result)\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "就地运算的加法(把x加到y上，直接修改y)：\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.9843,  2.5384, -0.9066],\n",
      "        [-0.2077,  0.9302, -0.7118],\n",
      "        [ 0.0234,  1.1288, -0.7171],\n",
      "        [-0.0322, -0.9226,  2.1789],\n",
      "        [ 1.4417,  0.5709,  2.4731]])\n"
     ]
    }
   ],
   "source": [
    "# 把x加到y\n",
    "y.add_(x)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\"><h4>注意</h4><p>所有就地修改一个tensor的operation都会以下划线结尾。\n",
    "    比如： ``x.copy_(y)``, ``x.t_()``, 都会修改``x``.</p></div>\n",
    "\n",
    "我们也可以使用类似numpy的下标运算：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([ 2.3707,  0.3905,  0.2491, -1.6052,  0.4827])\n"
     ]
    }
   ],
   "source": [
    "print(x[:, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果想resize或者reshape一个Tensor，我们可以使用``torch.view``:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])\n"
     ]
    }
   ],
   "source": [
    "x = torch.randn(4, 4)\n",
    "y = x.view(16)\n",
    "z = x.view(-1, 8)  # -1的意思是让PyTorch自己推断出第一维的大小。\n",
    "print(x.size(), y.size(), z.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果一个tensor只有一个元素，可以使用``.item()``来把它变成一个Python number\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([0.3835])\n",
      "0.3834681808948517\n"
     ]
    }
   ],
   "source": [
    "x = torch.randn(1)\n",
    "print(x)\n",
    "print(x.item())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**深入阅读:**\n",
    " \n",
    "  `这里 <http://pytorch.org/docs/torch>`的文档描述了上百个Tensor的运算，包括转置，索引，slicing，数学运算，线性代收，随机数等等。\n",
    "\n",
    "与NumPy数组的转换\n",
    "------------\n",
    "\n",
    "Torch Tensor和NumPy数组的转换非常容易。\n",
    "\n",
    "它们会共享内存地址，因此修改一方会影响另一方。\n",
    "\n",
    "把一个Torch Tensor转换成NumPy数组\n",
    "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([1., 1., 1., 1., 1.])\n"
     ]
    }
   ],
   "source": [
    "a = torch.ones(5)\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1. 1. 1. 1. 1.]\n"
     ]
    }
   ],
   "source": [
    "b = a.numpy()\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们修改一个会影响另外一个。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([2., 2., 2., 2., 2.])\n",
      "[2. 2. 2. 2. 2.]\n"
     ]
    }
   ],
   "source": [
    "a.add_(1)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "把NumPy数组转成Torch Tensor\n",
    "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2. 2. 2. 2. 2.]\n",
      "tensor([2., 2., 2., 2., 2.], dtype=torch.float64)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "a = np.ones(5)\n",
    "b = torch.from_numpy(a)\n",
    "np.add(a, 1, out=a)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "CPU上的所有类型的Tensor(除了CharTensor)都可以和Numpy数组来回转换。\n",
    "\n",
    "\n",
    "CUDA Tensor\n",
    "------------\n",
    "\n",
    "Tensor可以使用``.to``方法来移到任意设备上。\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([1.3835], device='cuda:0')\n",
      "tensor([1.3835], dtype=torch.float64)\n"
     ]
    }
   ],
   "source": [
    "# 如果有CUDA\n",
    "# 我们会使用``torch.device``来把tensors放到GPU上\n",
    "if torch.cuda.is_available():\n",
    "    device = torch.device(\"cuda\")          # 一个CUDA device对象。\n",
    "    y = torch.ones_like(x, device=device)  # 直接在GPU上创建tensor\n",
    "    x = x.to(device)                       # 也可以使用``.to(\"cuda\")``把一个tensor从CPU移到GPU上\n",
    "    z = x + y\n",
    "    print(z)\n",
    "    print(z.to(\"cpu\", torch.double))       # ``.to``也可以在移动的过程中修改dtype"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py3.6-env",
   "language": "python",
   "name": "py3.6-env"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
